home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Heretic Source / M_MISC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-13  |  17.3 KB  |  799 lines

  1.  
  2. // M_misc.c
  3.  
  4. #ifdef __NeXT__
  5. #include <libc.h>
  6. #else
  7. #include <sys/stat.h>
  8. #include <sys/types.h>
  9. #include <direct.h>
  10. #include <fcntl.h>
  11. #include <stdlib.h>
  12. #endif
  13.  
  14. #include <ctype.h>
  15.  
  16. #include "DoomDef.h"
  17. #include "soundst.h"
  18.  
  19. int myargc;
  20. char **myargv;
  21.  
  22. //---------------------------------------------------------------------------
  23. //
  24. // FUNC M_ValidEpisodeMap
  25. //
  26. //---------------------------------------------------------------------------
  27.  
  28. boolean M_ValidEpisodeMap(int episode, int map)
  29. {
  30.     if(episode < 1 || map < 1 || map > 9)
  31.     {
  32.         return false;
  33.     }
  34.     if(shareware)
  35.     { // Shareware version checks
  36.         if(episode != 1)
  37.         {
  38.             return false;
  39.         }
  40.     }
  41.     else if(ExtendedWAD)
  42.     { // Extended version checks
  43.         if(episode == 6)
  44.         {
  45.             if(map > 3)
  46.             {
  47.                 return false;
  48.             }
  49.         }
  50.         else if(episode > 5)
  51.         {
  52.             return false;
  53.         }
  54.     }
  55.     else
  56.     { // Registered version checks
  57.         if(episode == 4)
  58.         {
  59.             if(map != 1)
  60.             {
  61.                 return false;
  62.             }
  63.         }
  64.         else if(episode > 3)
  65.         {
  66.             return false;
  67.         }
  68.     }
  69.     return true;
  70. }
  71.  
  72. /*
  73. =================
  74. =
  75. = M_CheckParm
  76. =
  77. = Checks for the given parameter in the program's command line arguments
  78. =
  79. = Returns the argument number (1 to argc-1) or 0 if not present
  80. =
  81. =================
  82. */
  83.  
  84. int M_CheckParm (char *check)
  85. {
  86.     int     i;
  87.  
  88.     for (i = 1;i<myargc;i++)
  89.     {
  90.         if ( !strcasecmp(check, myargv[i]) )
  91.             return i;
  92.     }
  93.  
  94.     return 0;
  95. }
  96.  
  97.  
  98.  
  99. /*
  100. ===============
  101. =
  102. = M_Random
  103. =
  104. = Returns a 0-255 number
  105. =
  106. ===============
  107. */
  108.  
  109. unsigned char rndtable[256] = {
  110.     0,   8, 109, 220, 222, 241, 149, 107,  75, 248, 254, 140,  16,  66,
  111.     74,  21, 211,  47,  80, 242, 154,  27, 205, 128, 161,  89,  77,  36,
  112.     95, 110,  85,  48, 212, 140, 211, 249,  22,  79, 200,  50,  28, 188,
  113.     52, 140, 202, 120,  68, 145,  62,  70, 184, 190,  91, 197, 152, 224,
  114.     149, 104,  25, 178, 252, 182, 202, 182, 141, 197,   4,  81, 181, 242,
  115.     145,  42,  39, 227, 156, 198, 225, 193, 219,  93, 122, 175, 249,   0,
  116.     175, 143,  70, 239,  46, 246, 163,  53, 163, 109, 168, 135,   2, 235,
  117.     25,  92,  20, 145, 138,  77,  69, 166,  78, 176, 173, 212, 166, 113,
  118.     94, 161,  41,  50, 239,  49, 111, 164,  70,  60,   2,  37, 171,  75,
  119.     136, 156,  11,  56,  42, 146, 138, 229,  73, 146,  77,  61,  98, 196,
  120.     135, 106,  63, 197, 195,  86,  96, 203, 113, 101, 170, 247, 181, 113,
  121.     80, 250, 108,   7, 255, 237, 129, 226,  79, 107, 112, 166, 103, 241,
  122.     24, 223, 239, 120, 198,  58,  60,  82, 128,   3, 184,  66, 143, 224,
  123.     145, 224,  81, 206, 163,  45,  63,  90, 168, 114,  59,  33, 159,  95,
  124.     28, 139, 123,  98, 125, 196,  15,  70, 194, 253,  54,  14, 109, 226,
  125.     71,  17, 161,  93, 186,  87, 244, 138,  20,  52, 123, 251,  26,  36,
  126.     17,  46,  52, 231, 232,  76,  31, 221,  84,  37, 216, 165, 212, 106,
  127.     197, 242,  98,  43,  39, 175, 254, 145, 190,  84, 118, 222, 187, 136,
  128.     120, 163, 236, 249
  129. };
  130. int rndindex = 0;
  131. int prndindex = 0;
  132.  
  133. int P_Random (void)
  134. {
  135.     prndindex = (prndindex+1)&0xff;
  136.     return rndtable[prndindex];
  137. }
  138.  
  139. int M_Random (void)
  140. {
  141.     rndindex = (rndindex+1)&0xff;
  142.     return rndtable[rndindex];
  143. }
  144.  
  145. void M_ClearRandom (void)
  146. {
  147.     rndindex = prndindex = 0;
  148. }
  149.  
  150.  
  151. void M_ClearBox (fixed_t *box)
  152. {
  153.     box[BOXTOP] = box[BOXRIGHT] = MININT;
  154.     box[BOXBOTTOM] = box[BOXLEFT] = MAXINT;
  155. }
  156.  
  157. void M_AddToBox (fixed_t *box, fixed_t x, fixed_t y)
  158. {
  159.     if (x<box[BOXLEFT])
  160.         box[BOXLEFT] = x;
  161.     else if (x>box[BOXRIGHT])
  162.         box[BOXRIGHT] = x;
  163.     if (y<box[BOXBOTTOM])
  164.         box[BOXBOTTOM] = y;
  165.     else if (y>box[BOXTOP])
  166.         box[BOXTOP] = y;
  167. }
  168.  
  169.  
  170.  
  171. /*
  172. ==================
  173. =
  174. = M_WriteFile
  175. =
  176. ==================
  177. */
  178.  
  179. #ifndef O_BINARY
  180. #define O_BINARY 0
  181. #endif
  182.  
  183. boolean M_WriteFile (char const *name, void *source, int length)
  184. {
  185.     int handle, count;
  186.  
  187.     handle = open (name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
  188.     if (handle == -1)
  189.         return false;
  190.     count = write (handle, source, length);
  191.     close (handle);
  192.  
  193.     if (count < length)
  194.         return false;
  195.  
  196.     return true;
  197. }
  198.  
  199.  
  200. /*
  201. ==================
  202. =
  203. = M_ReadFile
  204. =
  205. ==================
  206. */
  207.  
  208. int M_ReadFile (char const *name, byte **buffer)
  209. {
  210.     int handle, count, length;
  211.     struct stat fileinfo;
  212.     byte        *buf;
  213.  
  214.     handle = open (name, O_RDONLY | O_BINARY, 0666);
  215.     if (handle == -1)
  216.         I_Error ("Couldn't read file %s", name);
  217.     if (fstat (handle,&fileinfo) == -1)
  218.         I_Error ("Couldn't read file %s", name);
  219.     length = fileinfo.st_size;
  220.     buf = Z_Malloc (length, PU_STATIC, NULL);
  221.     count = read (handle, buf, length);
  222.     close (handle);
  223.  
  224.     if (count < length)
  225.         I_Error ("Couldn't read file %s", name);
  226.  
  227.     *buffer = buf;
  228.     return length;
  229. }
  230.  
  231. //---------------------------------------------------------------------------
  232. //
  233. // PROC M_FindResponseFile
  234. //
  235. //---------------------------------------------------------------------------
  236.  
  237. #define MAXARGVS 100
  238.  
  239. void M_FindResponseFile(void)
  240. {
  241.     int i;
  242.  
  243.     for(i = 1; i < myargc; i++)
  244.     {
  245.         if(myargv[i][0] == '@')
  246.         {
  247.             FILE *handle;
  248.             int size;
  249.             int k;
  250.             int index;
  251.             int indexinfile;
  252.             char *infile;
  253.             char *file;
  254.             char *moreargs[20];
  255.             char *firstargv;
  256.  
  257.             // READ THE RESPONSE FILE INTO MEMORY
  258.             handle = fopen(&myargv[i][1], "rb");
  259.             if(!handle)
  260.             {
  261.  
  262.                 printf("\nNo such response file!");
  263.                 exit(1);
  264.             }
  265.             printf("Found response file %s!\n",&myargv[i][1]);
  266.             fseek (handle,0,SEEK_END);
  267.             size = ftell(handle);
  268.             fseek (handle,0,SEEK_SET);
  269.             file = malloc (size);
  270.             fread (file,size,1,handle);
  271.             fclose (handle);
  272.  
  273.             // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
  274.             for (index = 0,k = i+1; k < myargc; k++)
  275.                 moreargs[index++] = myargv[k];
  276.             
  277.             firstargv = myargv[0];
  278.             myargv = malloc(sizeof(char *)*MAXARGVS);
  279.             memset(myargv,0,sizeof(char *)*MAXARGVS);
  280.             myargv[0] = firstargv;
  281.             
  282.             infile = file;
  283.             indexinfile = k = 0;
  284.             indexinfile++;  // SKIP PAST ARGV[0] (KEEP IT)
  285.             do
  286.             {
  287.                 myargv[indexinfile++] = infile+k;
  288.                 while(k < size &&  
  289.  
  290.                     ((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
  291.                     k++;
  292.                 *(infile+k) = 0;
  293.                 while(k < size &&
  294.                     ((*(infile+k)<= ' ') || (*(infile+k)>'z')))
  295.                     k++;
  296.             } while(k < size);
  297.             
  298.             for (k = 0;k < index;k++)
  299.                 myargv[indexinfile++] = moreargs[k];
  300.             myargc = indexinfile;
  301.             // DISPLAY ARGS
  302.             if(M_CheckParm("-debug"))
  303.             {
  304.                 printf("%d command-line args:\n", myargc);
  305.                 for(k = 1; k < myargc; k++)
  306.                 {
  307.                     printf("%s\n", myargv[k]);
  308.                 }
  309.             }
  310.             break;
  311.         }
  312.     }
  313. }
  314.  
  315. //---------------------------------------------------------------------------
  316. //
  317. // PROC M_ForceUppercase
  318. //
  319. // Change string to uppercase.
  320. //
  321. //---------------------------------------------------------------------------
  322.  
  323. void M_ForceUppercase(char *text)
  324. {
  325.     char c;
  326.  
  327.     while((c = *text) != 0)
  328.     {
  329.         if(c >= 'a' && c <= 'z')
  330.         {
  331.             *text++ = c-('a'-'A');
  332.         }
  333.         else
  334.         {
  335.             text++;
  336.         }
  337.     }
  338. }
  339.  
  340. /*
  341. ==============================================================================
  342.  
  343.                             DEFAULTS
  344.  
  345. ==============================================================================
  346. */
  347.  
  348. int     usemouse;
  349. int     usejoystick;
  350.  
  351. extern  int     key_right, key_left, key_up, key_down;
  352. extern  int     key_strafeleft, key_straferight;
  353. extern  int     key_fire, key_use, key_strafe, key_speed;
  354. extern    int        key_flyup, key_flydown, key_flycenter;
  355. extern    int        key_lookup, key_lookdown, key_lookcenter;
  356. extern    int        key_invleft, key_invright, key_useartifact;
  357.  
  358. extern  int         mousebfire;
  359. extern  int         mousebstrafe;
  360. extern  int         mousebforward;
  361.  
  362. extern  int         joybfire;
  363. extern  int         joybstrafe;
  364. extern  int         joybuse;
  365. extern  int         joybspeed;
  366.  
  367. extern  int     viewwidth, viewheight;
  368.  
  369. int mouseSensitivity;
  370.  
  371. extern  int screenblocks;
  372.  
  373. extern char *chat_macros[10];
  374.  
  375. typedef struct
  376. {
  377.     char    *name;
  378.     int     *location;
  379.     int     defaultvalue;
  380.     int     scantranslate;      // PC scan code hack
  381.     int     untranslated;       // lousy hack
  382. } default_t;
  383.  
  384. #ifndef __NeXT__
  385. extern int snd_Channels;
  386. extern int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
  387. extern int snd_MusicDevice, // current music card # (index to dmxCodes)
  388.     snd_SfxDevice; // current sfx card # (index to dmxCodes)
  389.  
  390. extern int     snd_SBport, snd_SBirq, snd_SBdma;       // sound blaster variables
  391. extern int     snd_Mport;                              // midi variables
  392. #endif
  393.  
  394. default_t defaults[] =
  395. {
  396.     { "mouse_sensitivity", &mouseSensitivity, 5 },
  397.  
  398. #ifndef __NeXT__
  399.     { "sfx_volume", &snd_MaxVolume, 10},
  400.     { "music_volume", &snd_MusicVolume, 10},
  401. #endif
  402.  
  403. #ifdef __WATCOMC__
  404. #define SC_UPARROW              0x48
  405. #define SC_DOWNARROW            0x50
  406. #define SC_LEFTARROW            0x4b
  407. #define SC_RIGHTARROW           0x4d
  408. #define SC_RCTRL                0x1d
  409. #define SC_RALT                 0x38
  410. #define SC_RSHIFT               0x36
  411. #define SC_SPACE                0x39
  412. #define SC_COMMA                0x33
  413. #define SC_PERIOD               0x34
  414. #define SC_PAGEUP                0x49
  415. #define SC_INSERT                0x52
  416. #define SC_HOME                    0x47
  417. #define SC_PAGEDOWN                0x51
  418. #define SC_DELETE                0x53
  419. #define SC_END                    0x4f
  420. #define SC_ENTER                0x1c
  421.  
  422.     { "key_right", &key_right, SC_RIGHTARROW, 1 },
  423.     { "key_left", &key_left, SC_LEFTARROW, 1 },
  424.     { "key_up", &key_up, SC_UPARROW, 1 },
  425.     { "key_down", &key_down, SC_DOWNARROW, 1 },
  426.     { "key_strafeleft", &key_strafeleft, SC_COMMA, 1 },
  427.     { "key_straferight", &key_straferight, SC_PERIOD, 1 },
  428.     { "key_flyup", &key_flyup, SC_PAGEUP, 1 },
  429.     { "key_flydown", &key_flydown, SC_INSERT, 1 },
  430.     { "key_flycenter", &key_flycenter, SC_HOME, 1 },
  431.     { "key_lookup", &key_lookup, SC_PAGEDOWN, 1 },
  432.     { "key_lookdown", &key_lookdown, SC_DELETE, 1 },
  433.     { "key_lookcenter", &key_lookcenter, SC_END, 1 },
  434.     { "key_invleft", &key_invleft, 0x1a, 1 },
  435.     { "key_invright", &key_invright, 0x1b, 1 },
  436.     { "key_useartifact", &key_useartifact, SC_ENTER, 1 },
  437.  
  438.     { "key_fire", &key_fire, SC_RCTRL, 1 },
  439.     { "key_use", &key_use, SC_SPACE, 1 },
  440.     { "key_strafe", &key_strafe, SC_RALT, 1 },
  441.     { "key_speed", &key_speed, SC_RSHIFT, 1 },
  442. #endif
  443.  
  444. #ifdef __NeXT__
  445.     { "key_right", &key_right, KEY_RIGHTARROW },
  446.     { "key_left", &key_left, KEY_LEFTARROW },
  447.     { "key_up", &key_up, KEY_UPARROW },
  448.     { "key_down", &key_down, KEY_DOWNARROW },
  449.     { "key_strafeleft", &key_strafeleft, ',' },
  450.     { "key_straferight", &key_straferight, '.' },
  451.     { "key_flyup", &key_flyup, 'u' },
  452.     { "key_flydown", &key_flydown, 'j' },
  453.     { "key_flycenter", &key_flycenter, 'k' },
  454.     { "key_lookup", &key_lookup, 'm' },
  455.     { "key_lookdown", &key_lookdown, 'b' },
  456.     { "key_lookcenter", &key_lookcenter, 'n' },
  457.     { "key_invleft", &key_invleft, '[' },
  458.     { "key_invright", &key_invright, ']' },
  459.     { "key_useartifact", &key_useartifact, 13 },
  460.  
  461.     { "key_fire", &key_fire, ' ', 1 },
  462.     { "key_use", &key_use, 'x', 1 },
  463.     { "key_strafe", &key_strafe, 'c', 1 },
  464.     { "key_speed", &key_speed, 'z', 1 },
  465. #endif
  466.  
  467.     { "use_mouse", &usemouse, 1 },
  468.     { "mouseb_fire", &mousebfire, 0 },
  469.     { "mouseb_strafe", &mousebstrafe, 1 },
  470.     { "mouseb_forward", &mousebforward, 2 },
  471.  
  472.     { "use_joystick", &usejoystick, 0 },
  473.     { "joyb_fire", &joybfire, 0 },
  474.     { "joyb_strafe", &joybstrafe, 1 },
  475.     { "joyb_use", &joybuse, 3 },
  476.     { "joyb_speed", &joybspeed, 2 },
  477.  
  478.     { "screenblocks", &screenblocks, 10 },
  479.  
  480. #ifndef __NeXT__
  481.     { "snd_channels", &snd_Channels, 3 },
  482.     { "snd_musicdevice", &snd_DesiredMusicDevice, 0 },
  483.     { "snd_sfxdevice", &snd_DesiredSfxDevice, 0 },
  484.     { "snd_sbport", &snd_SBport, 544 },
  485.     { "snd_sbirq", &snd_SBirq, -1 },
  486.     { "snd_sbdma", &snd_SBdma, -1 },
  487.     { "snd_mport", &snd_Mport, -1 },
  488. #endif
  489.  
  490.     { "usegamma", &usegamma, 0 },
  491.  
  492.     { "chatmacro0", (int *) &chat_macros[0], (int) HUSTR_CHATMACRO0 },
  493.     { "chatmacro1", (int *) &chat_macros[1], (int) HUSTR_CHATMACRO1 },
  494.     { "chatmacro2", (int *) &chat_macros[2], (int) HUSTR_CHATMACRO2 },
  495.     { "chatmacro3", (int *) &chat_macros[3], (int) HUSTR_CHATMACRO3 },
  496.     { "chatmacro4", (int *) &chat_macros[4], (int) HUSTR_CHATMACRO4 },
  497.     { "chatmacro5", (int *) &chat_macros[5], (int) HUSTR_CHATMACRO5 },
  498.     { "chatmacro6", (int *) &chat_macros[6], (int) HUSTR_CHATMACRO6 },
  499.     { "chatmacro7", (int *) &chat_macros[7], (int) HUSTR_CHATMACRO7 },
  500.     { "chatmacro8", (int *) &chat_macros[8], (int) HUSTR_CHATMACRO8 },
  501.     { "chatmacro9", (int *) &chat_macros[9], (int) HUSTR_CHATMACRO9 }
  502. };
  503.  
  504. int numdefaults;
  505. char *defaultfile;
  506.  
  507. /*
  508. ==============
  509. =
  510. = M_SaveDefaults
  511. =
  512. ==============
  513. */
  514.  
  515. void M_SaveDefaults (void)
  516. {
  517.     int     i,v;
  518.     FILE    *f;
  519.  
  520.     f = fopen (defaultfile, "w");
  521.     if (!f)
  522.         return;         // can't write the file, but don't complain
  523.  
  524.     for (i=0 ; i<numdefaults ; i++)
  525.     {
  526. #ifdef __WATCOMC__
  527.         if (defaults[i].scantranslate)
  528.             defaults[i].location = &defaults[i].untranslated;
  529. #endif
  530.         if (defaults[i].defaultvalue > -0xfff
  531.           && defaults[i].defaultvalue < 0xfff)
  532.         {
  533.             v = *defaults[i].location;
  534.             fprintf (f,"%s\t\t%i\n",defaults[i].name,v);
  535.         } else {
  536.             fprintf (f,"%s\t\t\"%s\"\n",defaults[i].name,
  537.               * (char **) (defaults[i].location));
  538.         }
  539.     }
  540.  
  541.     fclose (f);
  542. }
  543.  
  544.  
  545. /*
  546. ==============
  547. =
  548. = M_LoadDefaults
  549. =
  550. ==============
  551. */
  552.  
  553. extern byte scantokey[128];
  554. extern char *basedefault;
  555.  
  556. void M_LoadDefaults (void)
  557. {
  558.     int     i, len;
  559.     FILE    *f;
  560.     char    def[80];
  561.     char        strparm[100];
  562.     char    *newstring;
  563.     int     parm;
  564.     boolean     isstring;
  565.  
  566. //
  567. // set everything to base values
  568. //
  569.     numdefaults = sizeof(defaults)/sizeof(defaults[0]);
  570.     for (i=0 ; i<numdefaults ; i++)
  571.         *defaults[i].location = defaults[i].defaultvalue;
  572.  
  573. //
  574. // check for a custom default file
  575. //
  576.     i = M_CheckParm("-config");
  577.     if(i && i<myargc-1)
  578.     {
  579.         defaultfile = myargv[i+1];
  580.         printf("default file: %s\n", defaultfile);
  581.     }
  582.     else if(cdrom)
  583.     {
  584.         defaultfile = "c:\\heretic.cd\\heretic.cfg";
  585.     }
  586.     else
  587.     {
  588.         defaultfile = basedefault;
  589.     }
  590.  
  591. //
  592. // read the file in, overriding any set defaults
  593. //
  594.     f = fopen (defaultfile, "r");
  595.     if (f)
  596.     {
  597.         while (!feof(f))
  598.         {
  599.             isstring = false;
  600.             if (fscanf (f, "%79s %[^\n]\n", def, strparm) == 2)
  601.             {
  602.               if (strparm[0] == '"')
  603.               {
  604.                 // get a string default
  605.                 isstring = true;
  606.                 len = strlen(strparm);
  607.                 newstring = (char *) malloc(len);
  608.                 strparm[len-1] = 0;
  609.                 strcpy(newstring, strparm+1);
  610.               }
  611.               else if (strparm[0] == '0' && strparm[1] == 'x')
  612.                   sscanf(strparm+2, "%x", &parm);
  613.               else
  614.                   sscanf(strparm, "%i", &parm);
  615.               for (i=0 ; i<numdefaults ; i++)
  616.                   if (!strcmp(def, defaults[i].name))
  617.                   {
  618.                       if (!isstring)
  619.                         *defaults[i].location = parm;
  620.                       else
  621.                         *defaults[i].location =
  622.                           (int) newstring;
  623.                       break;
  624.                   }
  625.             }
  626.         }
  627.  
  628.         fclose (f);
  629.     }
  630.  
  631.  
  632. #ifdef __WATCOMC__
  633.     for(i = 0; i < numdefaults; i++)
  634.     {
  635.         if(defaults[i].scantranslate)
  636.         {
  637.             parm = *defaults[i].location;
  638.             defaults[i].untranslated = parm;
  639.             *defaults[i].location = scantokey[parm];
  640.         }
  641.     }
  642. #endif
  643. }
  644.  
  645.  
  646. /*
  647. ==============================================================================
  648.  
  649.                         SCREEN SHOTS
  650.  
  651. ==============================================================================
  652. */
  653.  
  654.  
  655. typedef struct
  656. {
  657.     char    manufacturer;
  658.     char    version;
  659.     char    encoding;
  660.     char    bits_per_pixel;
  661.     unsigned short  xmin,ymin,xmax,ymax;
  662.     unsigned short  hres,vres;
  663.     unsigned char   palette[48];
  664.     char    reserved;
  665.     char    color_planes;
  666.     unsigned short  bytes_per_line;
  667.     unsigned short  palette_type;
  668.     char    filler[58];
  669.     unsigned char   data;           // unbounded
  670. } pcx_t;
  671.  
  672. /*
  673. ==============
  674. =
  675. = WritePCXfile
  676. =
  677. ==============
  678. */
  679.  
  680. void WritePCXfile (char *filename, byte *data, int width, int height, byte *palette)
  681. {
  682.     int     i, length;
  683.     pcx_t   *pcx;
  684.     byte        *pack;
  685.     
  686.     pcx = Z_Malloc (width*height*2+1000, PU_STATIC, NULL);
  687.  
  688.     pcx->manufacturer = 0x0a;   // PCX id
  689.     pcx->version = 5;           // 256 color
  690.     pcx->encoding = 1;      // uncompressed
  691.     pcx->bits_per_pixel = 8;        // 256 color
  692.     pcx->xmin = 0;
  693.     pcx->ymin = 0;
  694.     pcx->xmax = SHORT(width-1);
  695.     pcx->ymax = SHORT(height-1);
  696.     pcx->hres = SHORT(width);
  697.     pcx->vres = SHORT(height);
  698.     memset (pcx->palette,0,sizeof(pcx->palette));
  699.     pcx->color_planes = 1;      // chunky image
  700.     pcx->bytes_per_line = SHORT(width);
  701.     pcx->palette_type = SHORT(2);       // not a grey scale
  702.     memset (pcx->filler,0,sizeof(pcx->filler));
  703.  
  704. //
  705. // pack the image
  706. //
  707.     pack = &pcx->data;
  708.  
  709.     for (i=0 ; i<width*height ; i++)
  710.         if ( (*data & 0xc0) != 0xc0)
  711.             *pack++ = *data++;
  712.         else
  713.         {
  714.             *pack++ = 0xc1;
  715.             *pack++ = *data++;
  716.         }
  717.  
  718. //
  719. // write the palette
  720. //
  721.     *pack++ = 0x0c; // palette ID byte
  722.     for (i=0 ; i<768 ; i++)
  723.         *pack++ = *palette++;
  724.  
  725. //
  726. // write output file
  727. //
  728.     length = pack - (byte *)pcx;
  729.     M_WriteFile (filename, pcx, length);
  730.  
  731.     Z_Free (pcx);
  732. }
  733.  
  734.  
  735. //==============================================================================
  736.  
  737. /*
  738. ==================
  739. =
  740. = M_ScreenShot
  741. =
  742. ==================
  743. */
  744.  
  745. void M_ScreenShot (void)
  746. {
  747.     int     i;
  748.     byte    *linear;
  749.     char    lbmname[12];
  750.     byte *pal;
  751.  
  752. #ifdef _WATCOMC_
  753.     extern  byte *pcscreen;
  754. #endif
  755. //
  756. // munge planar buffer to linear
  757. //
  758. #ifdef _WATCOMC_
  759.     linear = pcscreen;
  760. #else
  761.     linear = screen;
  762. #endif
  763. //
  764. // find a file name to save it to
  765. //
  766.     strcpy(lbmname,"HRTIC00.pcx");
  767.  
  768.     for (i=0 ; i<=99 ; i++)
  769.     {
  770.         lbmname[5] = i/10 + '0';
  771.         lbmname[6] = i%10 + '0';
  772.         if (access(lbmname,0) == -1)
  773.             break;  // file doesn't exist
  774.     }
  775.     if (i==100)
  776.         I_Error ("M_ScreenShot: Couldn't create a PCX");
  777.  
  778. //
  779. // save the pcx file
  780. //
  781. #ifdef __WATCOMC__
  782.     pal = (byte *)Z_Malloc(768, PU_STATIC, NULL);
  783.     outp(0x3c7, 0);
  784.     for(i = 0; i < 768; i++)
  785.     {
  786.         *(pal+i) = inp(0x3c9)<<2;
  787.     }
  788. #else
  789.     pal = (byte *)W_CacheLumpName("PLAYPAL", PU_CACHE);
  790. #endif
  791.  
  792.     WritePCXfile (lbmname, linear, SCREENWIDTH, SCREENHEIGHT
  793.         , pal);
  794.  
  795.     players[consoleplayer].message = "SCREEN SHOT";
  796. #ifdef __WATCOMC__
  797.     Z_Free(pal);
  798. #endif
  799. }
  800.